package com.codemonkey.lq.common.util;

import java.util.List;

import javax.swing.JDialog;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StringUtil;

/**
 * <p>
 * 打印类的继承关系(自下而上, 即从传入类开始)
 * 
 * @author LQ
 *
 */
class PrintClassHierarchy2 {
	private static final String PADDING = "        ";

	@SuppressWarnings("unused")
	private static final String PADDING_WITH_COLUMN = "   |    ";

	private static final String PADDING_WITH_ENTRY = "   |--- ";

	public static void main(String[] args) {
		print(getClassHierarchy(JDialog.class));
	}

	public static final ClassInfo getClassHierarchy(final Class<?> clazz) {
		return new ClassInfo(clazz);
	}

	public static final void print(ClassInfo classInfo) {
		print(classInfo, 0);
	}

	static final void print(ClassInfo classInfo, int level) {
		if (null == classInfo) {
			return;
		}
		if ( classInfo.getSuperCls() == null && classInfo.getInterfaceInfos().isEmpty()) {
			return;
		}

		if (0 == level) {
			// NO OP
		} else {
			System.out.print(StringUtil.repeat(PADDING, level));
			System.out.print(PADDING_WITH_ENTRY);
		}
		Console.log(formatCls(classInfo.getCurrentCls()));

		if (null != classInfo.getSuperCls()) {
			// NO OP
		}

		if (!classInfo.getInterfaceInfos().isEmpty()) {
			for (ClassInfo ci : classInfo.getInterfaceInfos()) {
				Class<?> currentCls = ci.getCurrentCls();
				Console.log("{}{}{}", StringUtil.repeat(PADDING, level + 1), PADDING_WITH_ENTRY,
						formatInterface(currentCls));
				for (ClassInfo ii : ci.getInterfaceInfos()) {
					print(ii, level + 2);
				}
			}
		}

		print(classInfo.getSuperClsInfo(), level + 1);
	}

	private static String formatCls(final Class<?> cls) {
		return StringUtil.format("{}.{}-[C]", cls.getPackage().getName(), cls.getSimpleName());
	}

	private static String formatInterface(final Class<?> cls) {
		return StringUtil.format("{}.{}-[I]", cls.getPackage().getName(), cls.getSimpleName());
	}

	// ============== INNER CLASS
	private static class ClassInfo {
		private final Class<?> currentCls;

		private final List<Class<?>> interfaces;

		private final Class<?> superCls;

		// =====
		private final ClassInfo superClsInfo;

		private final List<ClassInfo> interfaceInfos;

		public ClassInfo(Class<?> currentCls) {
			super();
			this.currentCls = currentCls;
			this.interfaces = CollectionUtil.newArrayList(currentCls.getInterfaces());
			this.interfaceInfos = CollectionUtil.newArrayList();
			for (Class<?> cls : this.interfaces) {
				this.interfaceInfos.add(new ClassInfo(cls));
			}

			if (null == currentCls || null != currentCls.getSuperclass()) {
				this.superCls = currentCls.getSuperclass();
				this.superClsInfo = new ClassInfo(this.superCls);
			} else {
				this.superCls = null;
				this.superClsInfo = null;
			}
		}

		public Class<?> getCurrentCls() {
			return currentCls;
		}

		public Class<?> getSuperCls() {
			return superCls;
		}

		// =====
		public ClassInfo getSuperClsInfo() {
			return superClsInfo;
		}

		public List<ClassInfo> getInterfaceInfos() {
			return interfaceInfos;
		}

		@Override
		public String toString() {
			return ObjectUtil.toString(BeanUtil.beanToMap(this));
		}
	}
}